package com.ctshk.rpc.order.train.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.CurrencyIdCode;
import com.ctshk.common.constant.CurrencyRateExchangeConstant;
import com.ctshk.common.dto.Result;
import com.ctshk.common.dto.payment.CallPayDTO;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.Currency;
import com.ctshk.common.enums.bus.BusConst;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.mail.core.MailTemplate;
import com.ctshk.common.model.AppReq;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.req.pay.NotifyConsumeReq;
import com.ctshk.common.service.support.BaseService;
import com.ctshk.common.utils.*;
import com.ctshk.rpc.booking.enums.SupplierReserveTypeEnum;
import com.ctshk.rpc.booking.req.system.train.add.SupplierOrderSystemTrainAddReq;
import com.ctshk.rpc.booking.req.system.train.add.SupplierSystemOrderTrainAddReq;
import com.ctshk.rpc.booking.req.system.train.add.SupplierSystemOrderTrainTicketAddReq;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.finance.json.FileJson;
import com.ctshk.rpc.finance.req.bill.BillAddCollectionReq;
import com.ctshk.rpc.finance.req.onaccount.UseQuotaReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.finance.service.IFinanceOnAccountCurrencyQuotaService;
import com.ctshk.rpc.insurance.service.IInsuranceService;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.order.train.dto.TrainOrderDetailAppDTO;
import com.ctshk.rpc.order.train.dto.TrainOrderDetailDTO;
import com.ctshk.rpc.order.train.dto.TrainOrderTouristAppDTO;
import com.ctshk.rpc.order.train.entity.*;
import com.ctshk.rpc.order.train.manager.TrainOrderManager;
import com.ctshk.rpc.order.train.mapper.*;
import com.ctshk.rpc.order.train.req.TrainCancelOrderAppReq;
import com.ctshk.rpc.order.train.req.TrainManualOrderAppReq;
import com.ctshk.rpc.order.train.req.TrainOrderTouristAppReq;
import com.ctshk.rpc.order.train.req.TrainOrderWriteReq;
import com.ctshk.rpc.order.train.service.ITrainOrderAppService;
import com.ctshk.rpc.payment.enums.PayCurrency;
import com.ctshk.rpc.payment.enums.PayOrderStatus;
import com.ctshk.rpc.payment.enums.PaymentMethod;
import com.ctshk.rpc.payment.req.PayCommonReq;
import com.ctshk.rpc.payment.service.IPayService;
import com.ctshk.rpc.system.dto.MainDataCurrencyListDTO;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.dto.member.ContactQueryDTO;
import com.ctshk.rpc.system.req.DispatchOrderRuleGetUserReq;
import com.ctshk.rpc.system.req.MainDataCurrencyListReq;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberQueryReq;
import com.ctshk.rpc.system.service.*;
import com.ctshk.rpc.train.dto.*;
import com.ctshk.rpc.train.dto.es.TrainNumberSeatLevelCacheDTO;
import com.ctshk.rpc.train.dto.es.TrainStopStationCacheDTO;
import com.ctshk.rpc.train.dto.h5.MainDataManualSystemAppDTO;
import com.ctshk.rpc.train.dto.h5.TrainProductH5DTO;
import com.ctshk.rpc.train.dto.h5.TrainProductSeatH5DTO;
import com.ctshk.rpc.train.enums.MtrTrainNumber;
import com.ctshk.rpc.train.enums.SeatAliApiEnum;
import com.ctshk.rpc.train.req.TrainTicketQueryReq;
import com.ctshk.rpc.train.service.ITrainApiService;
import com.ctshk.rpc.train.service.ITrainNumberService;
import com.ctshk.rpc.train.service.ITrainProductCostService;
import com.ctshk.rpc.train.service.ITrainProductService;
import com.ctshk.rpc.user.service.IOrderEsService;
import com.ctshk.rpc.user.service.IUserSmsService;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import com.github.houbb.opencc4j.util.ZhConverterUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 火车票订单表 服务实现类
 * </p>
 *
 * @author 彭柳霖
 * @since 2021-03-17
 */
@Slf4j
@DubboService
public class TrainOrderAppServiceImpl extends ServiceImpl<TrainOrderMapper, TrainOrder> implements ITrainOrderAppService, BaseService {

    @Autowired
    private TrainOrderTouristMapper trainOrderTouristMapper;

    @Autowired
    private TrainOrderCollectionMapper trainOrderCollectionMapper;

    @Autowired
    private TrainOrderRefundMapper trainOrderRefundMapper;

    @Autowired
    private TrainManualOrderMapper trainManualOrderMapper;

    @Autowired
    private TrainOrderMapper trainOrderMapper;

    @Autowired
    private TrainOrderReceiptMapper trainOrderReceiptMapper;

    @DubboReference
    private ITrainNumberService trainNumberService;

    @DubboReference
    private ITrainProductService trainProductService;

    @DubboReference
    private ITrainProductCostService trainProductCostService;

    @DubboReference
    ICrmMemberService crmMemberService;

    @DubboReference
    private IMainDataCurrencyService iMainDataCurrencyService;

    @DubboReference
    ISysDepartmentService sysDepartmentService;

    @DubboReference
    ISysUserService sysUserService;

    @DubboReference
    IOperateBankPreferenceService operateBankPreferenceService;

    @DubboReference
    ISupplierOrderService supplierOrderService;

    @DubboReference
    private ISysUserService iSysUserService;

    @DubboReference
    private IFinanceBillService iFinanceBillService;

    @DubboReference
    IMainDataCurrencyService mainDataCurrencyService;

    @DubboReference
    ISysApprovalService sysApprovalService;

    @Autowired
    private MailTemplate mailTemplate;

    @DubboReference
    private IInsuranceService iInsuranceService;

    @DubboReference
    private IPayService payService;

    @DubboReference(retries = 0)
    private ITrainApiService iTrainApiService;

    @DubboReference
    private IDispatchOrderRuleService iDispatchOrderRuleService;

    @DubboReference
    private IOrderEsService orderEsService;

    @DubboReference
    IDispatchOrderRuleService dispatchOrderRuleService;

    @DubboReference
    private IFinanceOnAccountCurrencyQuotaService onAccountCurrencyQuotaService;

    @DubboReference
    private IUserSmsService userSmsService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Long> writeTrainOrder(TrainOrderWriteReq trainOrderWriteReq, TokenUser user, AppReq appReq) {
        log.info("【火车票订单APP服务-填写订单页】方法入参, data:{}", JSON.toJSONString(trainOrderWriteReq));
        List<TrainOrderTourist> busOrderTouristList = EntityUtil.copyList(trainOrderWriteReq.getTrainOrderTouristReqList(), TrainOrderTourist.class);
        int adultNumber = 0;
        int childrenNumber = 0;

        // 保险总额
        BigDecimal insurancePriceTotal = BigDecimal.ZERO;
        for (TrainOrderTourist tourist : busOrderTouristList) {
            String touristType = tourist.getTouristType();
            if ("1".equals(touristType)) {
                adultNumber++;
            } else if ("2".equals(touristType)) {
                childrenNumber++;
            }
            insurancePriceTotal = tourist.getInsurancePrice() == null ? BigDecimal.ZERO : tourist.getInsurancePrice();
        }

        // 获取火车产品相关信息
        TrainProductDTO trainProductDTO = trainProductService.queryDetail(trainOrderWriteReq.getTrainProductId());
        log.info("【火车票订单APP服务-填写订单页】查询产品信息响应, data:{}", JSON.toJSONString(trainProductDTO));
        if (trainProductDTO == null) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14004);
        }
        //获取预定设置
        TrainProductReservationSettingsDTO trainProductReservationSettingsDTO = trainProductDTO.getTrainProductReservationSettingsDTO();
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        int touristNumber = trainOrderWriteReq.getTrainOrderTouristReqList().size();

        // 预定日期
        LocalDate effectiveDate = trainOrderWriteReq.getEffectiveDate();
        // 查询加幅后的价格，售卖类型，余票
//        trainPriceRemainderDTO = trainProductService.selectSelfPriceRemainderAndLock(trainOrderWriteReq.getTrainProductId(), touristNumber, user.getId(), effectiveDate);
        ChannelMainData channelMainData = ChannelMainData.getById(appReq.getChannelId());
        TrainPriceRemainderDTO trainPriceRemainderDTO = trainProductService.selectAppPriceRemainderAndLock(trainOrderWriteReq.getTrainProductId(), touristNumber, effectiveDate, channelMainData);
        log.info("【火车票订单APP服务-填写订单页】查询APP产品价格信息响应, data:{}", JSON.toJSONString(trainPriceRemainderDTO));
        TrainOrder trainOrder = EntityUtil.copy(trainOrderWriteReq, TrainOrder.class);

        // 将火车产品相关数据设置到火车订单中
        trainOrder.setEffectiveTime(LocalDateTime.of(effectiveDate, LocalTime.now()));
        trainOrder.setRailwayCorporationId(trainProductDTO.getRailwayCorporationId());
        trainOrder.setRailwayCorporationName(trainProductDTO.getRailwayCorporationName());
        trainOrder.setTrainNumberId(trainProductDTO.getTrainNumberId());
        trainOrder.setTrainNumberName(trainProductDTO.getTrainNumberName());
        trainOrder.setDepartureCityId(trainProductDTO.getDepartureCityId());
        trainOrder.setDepartureCityName(trainProductDTO.getDepartureCityName());
        trainOrder.setArriveCityId(trainProductDTO.getArriveCityId());
        trainOrder.setArriveCityName(trainProductDTO.getArriveCityName());
        trainOrder.setBoardingStationId(trainProductDTO.getBoardingStationId());
        trainOrder.setBoardingStationName(trainProductDTO.getBoardingStationName());
        trainOrder.setAlightingStationId(trainProductDTO.getAlightingStationId());
        trainOrder.setAlightingStationName(trainProductDTO.getAlightingStationName());
        trainOrder.setSeatLevelId(trainProductDTO.getSeatLevelId());
        trainOrder.setSeatLevelName(trainProductDTO.getSeatLevelName());
//        trainOrder.setReceiptTitle(trainOrderWriteReq.getReceiptTitle());
//        trainOrder.setOfficeId(trainOrderWriteReq.getOfficeId());
        String inquiryNumber = generatorInquiryNumber();
        trainOrder.setQueryNumber(inquiryNumber);
        // 设置产品来源
        trainOrder.setProductType(trainProductDTO.getProductSource());
        // 设置出发日期时间
        // 获取火车产品的出发时间加上预定的日期
        LocalDateTime departureTime = trainProductDTO.getDepartureTime();
        trainOrder.setDepartureTime(LocalDateTime.of(effectiveDate, departureTime.toLocalTime()));
        trainOrder.setSource(appReq.getOrderSource());

        // 成人服务价格
        BigDecimal adultServiceChargePrice = BigDecimal.ZERO;
        // 小童服务价格
        BigDecimal childrenServiceChargePrice = BigDecimal.ZERO;
        // 预定设置不为空，取服务费
        if (trainProductReservationSettingsDTO != null) {
            // 计算服务费
            Integer serviceChargeType = trainProductReservationSettingsDTO.getServiceChargeType();
            BigDecimal serviceChargePrice = trainProductReservationSettingsDTO.getServiceChargePrice() == null ? BigDecimal.ZERO : trainProductReservationSettingsDTO.getServiceChargePrice();
            if (serviceChargeType == 2) {
                // 百分比
                BigDecimal per = serviceChargePrice.divide(new BigDecimal("100"));
                BigDecimal adultPrimePrice = trainPriceRemainderDTO.getAdultPrimePrice() == null ? BigDecimal.ZERO : trainPriceRemainderDTO.getAdultPrimePrice();
                BigDecimal childrenPrimePrice = trainPriceRemainderDTO.getChildrenPrimePrice() == null ? BigDecimal.ZERO : trainPriceRemainderDTO.getChildrenPrimePrice();
                adultServiceChargePrice = adultPrimePrice.multiply(per);
                childrenServiceChargePrice = childrenPrimePrice.multiply(per);
            } else if (serviceChargeType == 1) {
                // 加数值
                adultServiceChargePrice = serviceChargePrice;
                childrenServiceChargePrice = serviceChargePrice;
            }
        }

        //计算总价
        BigDecimal adultPriceTotal = trainPriceRemainderDTO.getAdultPrice().add(adultServiceChargePrice).multiply(new BigDecimal(Integer.toString(adultNumber)));
        BigDecimal childrenPriceTotal = trainPriceRemainderDTO.getChildrenPrice().add(childrenServiceChargePrice).multiply(new BigDecimal(Integer.toString(childrenNumber)));
        BigDecimal orderAmount = adultPriceTotal.add(childrenPriceTotal).add(insurancePriceTotal);
        // 计算应收金额
        BigDecimal receivableAmount = buildReceivableAmount(trainOrder, orderAmount);
        // 计算付款到期时间,+30分钟
        trainOrder.setPayExpireDate(nowLocalDateTime.plusMinutes(30));
        Long id = SnowflakeIdWorker.nextId();
        trainOrder.setId(id);
        trainOrder.setTrainId(trainOrderWriteReq.getTrainProductId());
        trainOrder.setOrderAmount(orderAmount);
        trainOrder.setReceivableAmount(receivableAmount);
        trainOrder.setNumber(touristNumber);
        trainOrder.setContactName(trainOrder.getSurname() + trainOrder.getName());
        if (trainProductReservationSettingsDTO != null && trainProductReservationSettingsDTO.getIsConfirm() == 1) {
            // 立即确认
            trainOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
        } else {
            // 二次确认，预定状态为待确认
            trainOrder.setScheduledStatus(OrderScheduledStatus.CONFIRM_RESERVE.getCode());
        }
        //trainOrder.setScheduledStatus(0); //初始预定状态
        trainOrder.setPaymentStatus(OrderPaymentStatus.UN_PAYMENT.getCode()); //待付款
        trainOrder.setCancelStatus(0); //初始未取消
        trainOrder.setSalesMethods(1);//销售方式(1：单品销售 2：打包销售)
        trainOrder.setIsDeleted(IsDeletedCode.NO.getCode());

        // 获取销售人员
        DispatchOrderRuleGetUserReq dispatchOrderRuleGetUserReq = new DispatchOrderRuleGetUserReq();
        dispatchOrderRuleGetUserReq.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        dispatchOrderRuleGetUserReq.setCompanyType(appReq.getCompanyType());
        Result<Long> result = iDispatchOrderRuleService.getDispatchUserId(dispatchOrderRuleGetUserReq);
        if (!result.isSuccess()) {
            log.error("火车票下单 - 获取销售人失败msg:{}" + result.getMsg());
            throw new BusinessException(SystemError.getDefined(result.getCode()));
        }
        UserDTO saleUser = sysUserService.queryCacheUser(result.getData());
        //获取火车订单编号
        trainOrder.setOrderNumber(buildOrderNumber(saleUser, nowLocalDateTime));
        trainOrder.setCreateId(result.getData());
        trainOrder.setGmtCreate(nowLocalDateTime);
        trainOrder.setGmtModified(nowLocalDateTime);
        trainOrder.setOrderType(0);
        // C端下单用户id
        trainOrder.setUserId(user == null ? null : user.getId());
/*        trainOrder.setSalesmanId(saleUser.getId());
        trainOrder.setSalesmanName(saleUser.getUsername());
        trainOrder.setUserId(saleUser.getId());*/
        trainOrder.setCreateId(result.getData());
        String quiryNumber = generatorInquiryNumber();
        trainOrder.setQueryNumber(quiryNumber);
        this.baseMapper.insert(trainOrder);

        //生成收据单号
        insertReceipt(trainOrder, saleUser, LocalDateTime.now(),trainOrderWriteReq.getReceiptTitle(),trainOrderWriteReq.getOfficeId());

        BigDecimal finalAdultServiceChargePrice = adultServiceChargePrice;
        BigDecimal finalChildrenServiceChargePrice = childrenServiceChargePrice;
        busOrderTouristList.forEach(tourist -> {
            tourist.setId(SnowflakeIdWorker.nextId());
            tourist.setOrderId(id);
            // 成人
            if ("1".equals(tourist.getTouristType())) {
                BigDecimal adultPrice = trainPriceRemainderDTO.getAdultPrice();
                tourist.setTicketPrice(adultPrice);
                tourist.setServiceChargePrice(finalAdultServiceChargePrice);
            } else if ("2".equals(tourist.getTouristType())) {
                tourist.setServiceChargePrice(finalChildrenServiceChargePrice);
                tourist.setTicketPrice(trainPriceRemainderDTO.getChildrenPrice());
            }
            trainOrderTouristMapper.insert(tourist);
        });

        sendOrderToAppUser(id);
        return Result.success(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Long> addTrainManualOrder(TrainManualOrderAppReq trainOrderWriteReq, TokenUser user, ChannelMainData chinaTravel) {
        // 1. 获取阿里云产品信息
        List<TrainProductSeatH5DTO> seatH5DTOList = getAliTrainList(trainOrderWriteReq);
        seatH5DTOList = seatH5DTOList.stream().filter(trainStation -> {
            return trainStation.getBoardingStationName().equals(trainOrderWriteReq.getBoardingStationName())
                    && trainStation.getAlightingStationName().equals(trainOrderWriteReq.getAlightingStationName())
                    && trainStation.getTrainNumberName().equals(trainOrderWriteReq.getTrainNumberName());
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(seatH5DTOList)) {
            return Result.failed(SystemError.TRAIN_PRODUCT_14036);
        }
        TrainProductSeatH5DTO trainProductSeatH5DTO = seatH5DTOList.get(0);

        // 1.1 选定坐席等级
        List<TrainNumberSeatLevelCacheDTO> trainNumberSeatLevelCacheDTOS = trainProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS().stream().filter(productSeat -> {
            return productSeat.getSeatLevelName().equals(trainOrderWriteReq.getSeatLevelName()) ||
                    ZhConverterUtil.toTraditional(productSeat.getSeatLevelName()).equals(trainOrderWriteReq.getSeatLevelName());
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(trainNumberSeatLevelCacheDTOS)) {
            return Result.failed(SystemError.TRAIN_PRODUCT_14036);
        }
        trainProductSeatH5DTO.setTrainNumberSeatLevelCacheDTOS(trainNumberSeatLevelCacheDTOS);


        //2. 添加订单
        TrainOrder trainOrder = new TrainOrder();
        // C端下单用户id
        trainOrder.setUserId(user == null ? null : user.getId());
        BeanUtils.copyProperties(trainOrderWriteReq, trainOrder);
        Long orderId = SnowflakeIdWorker.nextId();
        trainOrder.setId(orderId);
        // 获取销售人员
        DispatchOrderRuleGetUserReq dispatchOrderRuleGetUserReq = new DispatchOrderRuleGetUserReq();
        dispatchOrderRuleGetUserReq.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        dispatchOrderRuleGetUserReq.setCompanyType(CompanyType.HK_CT.getCode());
        Result<Long> result = iDispatchOrderRuleService.getDispatchUserId(dispatchOrderRuleGetUserReq);
        if (!result.isSuccess()) {
            log.error("火车票下单 - 获取销售人失败msg:{}" + result.getMsg());
            throw new BusinessException(SystemError.getDefined(result.getCode()));
        }
        UserDTO saleUser = sysUserService.queryCacheUser(result.getData());
        trainOrder.setCreateId(result.getData());
        LocalDateTime now = LocalDateTime.now();
        trainOrder.setGmtCreate(now);
        trainOrder.setGmtModified(now);
        trainOrder.setSalesmanId(saleUser.getId());
        trainOrder.setSalesmanName(saleUser.getUsername());
        trainOrder.setUserId(user == null ? null : user.getId());
        trainOrder.setProductType(ProductType.API_PRODUCT.getCode());
        //获取火车订单编号
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        trainOrder.setOrderNumber(buildOrderNumber(saleUser, nowLocalDateTime));

        String inquiryNumber = generatorInquiryNumber();
        trainOrder.setQueryNumber(inquiryNumber);

        //2.1 设置出发日期时间 产品的出发时间加上预定的日期
        LocalDate effectiveDate = trainOrderWriteReq.getEffectiveDate();
        LocalDateTime departureTime = trainProductSeatH5DTO.getDepartureTime();
        trainOrder.setDepartureTime(LocalDateTime.of(effectiveDate, departureTime.toLocalTime()));
        trainOrder.setEffectiveTime(LocalDateTime.of(effectiveDate, LocalTime.now()));
        trainOrder.setTerminusTime(LocalDateTime.of(effectiveDate, trainProductSeatH5DTO.getTerminusTime().toLocalTime()));
        trainOrder.setSource(chinaTravel.equals(ChannelMainData.CHINA_TRAVEL) ? OrderSource.PC_NET.getCode() : OrderSource.H5.getCode());

        //2.2 计算总价
        List<TrainOrderTouristAppReq> touristReqList = trainOrderWriteReq.getTrainOrderTouristReqList();
        int adultNumber = 0;
        int childrenNumber = 0;
        for (TrainOrderTouristAppReq tourist : touristReqList) {
            String touristType = tourist.getTouristType();
            if ("1".equals(touristType)) {
                adultNumber++;
            } else if ("2".equals(touristType)) {
                childrenNumber++;
            } else {
                throw new BusinessException(SystemError.TRAIN_PRODUCT_14037);
            }
        }

        BigDecimal serviceChargePrice = BigDecimal.ZERO;
        for (MainDataManualSystemAppDTO manual : trainNumberSeatLevelCacheDTOS.get(0).getMainDataManualSystemAppDTOList()) {
            if (trainOrderWriteReq.getSystemId().equals(manual.getId())) {
                serviceChargePrice = manual.getServiceChargeAmount();
            }
        }
        /*BigDecimal adultPriceTotal = trainNumberSeatLevelCacheDTOS.get(0).getPcPrice().add(serviceChargePrice).multiply(new BigDecimal(Integer.toString(adultNumber)));
        BigDecimal childrenPriceTotal = trainNumberSeatLevelCacheDTOS.get(0).getPcChildPrice().add(serviceChargePrice).multiply(new BigDecimal(Integer.toString(childrenNumber)));
        BigDecimal orderAmount = adultPriceTotal.add(childrenPriceTotal);*/

        trainOrder.setOrderAmount(trainOrderWriteReq.getPrice());
        trainOrder.setReceivableAmount(trainOrderWriteReq.getPrice());
        trainOrder.setNumber(touristReqList.size());
        trainOrder.setContactName(trainOrder.getSurname() + trainOrder.getName());

        // 计算付款到期时间,+30分钟
        trainOrder.setPayExpireDate(nowLocalDateTime.plusMinutes(30));

        // 二次确认，预定状态为待确认
        trainOrder.setScheduledStatus(OrderScheduledStatus.CONFIRM_RESERVE.getCode());
        //trainOrder.setScheduledStatus(0); //初始预定状态
        trainOrder.setPaymentStatus(OrderPaymentStatus.UN_PAYMENT.getCode()); //待付款
        trainOrder.setCancelStatus(0); //初始未取消
        trainOrder.setSalesMethods(1);//销售方式(1：单品销售 2：打包销售)
        trainOrder.setIsDeleted(IsDeletedCode.NO.getCode());
        trainOrder.setOrderType(1); // 设置外挂单标识
//        trainOrder.setReceiptTitle(trainOrderWriteReq.getReceiptTitle());
//        trainOrder.setOfficeId(trainOrderWriteReq.getOfficeId());
        trainOrderMapper.insert(trainOrder);

        //生成收据单号
        insertReceipt(trainOrder, saleUser, LocalDateTime.now(),trainOrderWriteReq.getReceiptTitle(),trainOrderWriteReq.getOfficeId());

        //3. 添加外挂订单信息
        TrainManualOrder trainManualOrder = new TrainManualOrder();
        trainManualOrder.setId(SnowflakeIdWorker.nextId());
        trainManualOrder.setOrderId(orderId);
        trainManualOrder.setSystemId(trainOrderWriteReq.getSystemId());
        trainManualOrder.setSystemName(MainDataManualSystemCode.parseValue(trainOrderWriteReq.getSystemId()));
        trainManualOrder.setServiceAomunt(serviceChargePrice);
        trainManualOrderMapper.insert(trainManualOrder);

        //4. 添加订单旅客信息
        for (TrainOrderTouristAppReq trainOrderTouristReq : touristReqList) {
            TrainOrderTourist trainOrderTourist = new TrainOrderTourist();
            BeanUtils.copyProperties(trainOrderTouristReq, trainOrderTourist);
            trainOrderTourist.setId(SnowflakeIdWorker.nextId());
            trainOrderTourist.setOrderId(orderId);
            // 成人
            if ("1".equals(trainOrderTourist.getTouristType())) {
                BigDecimal adultPrice = trainNumberSeatLevelCacheDTOS.get(0).getPcPrice();
                trainOrderTourist.setTicketPrice(adultPrice);
                trainOrderTourist.setServiceChargePrice(serviceChargePrice);
            } else if ("2".equals(trainOrderTourist.getTouristType())) {
                trainOrderTourist.setServiceChargePrice(serviceChargePrice);
                trainOrderTourist.setTicketPrice(trainNumberSeatLevelCacheDTOS.get(0).getPcChildPrice());
            }
            trainOrderTouristMapper.insert(trainOrderTourist);
        }
        sendOrderToAppUser(orderId);
        return Result.success(orderId);
    }

    private List<TrainProductSeatH5DTO> getAliTrainList(TrainManualOrderAppReq req) {
        List<TrainProductSeatH5DTO> trainProductSeatH5DTOS = new ArrayList<>();

        // 获取汇率
        MainDataCurrencyQueryDTO exchangeRate = getExchangeRateByCurrencyId(CurrencyIdCode.CNY.getCode());
        TrainTicketQueryReq queryReq = new TrainTicketQueryReq();
        queryReq.setDate(req.getEffectiveDate().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        queryReq.setStart(ZhConverterUtil.toSimple(req.getBoardingStationName()));
        queryReq.setEnd(ZhConverterUtil.toSimple(req.getAlightingStationName()));
        List<ApiTrainProductDTO> list;
        try {
            list = iTrainApiService.getTrainTicketList(queryReq);
        } catch (Exception e) {
            log.error("api查询火车票异常", e);
            return null;
        }
        list = list.stream().filter(trainStation -> {
            // 过滤不符合的出发站,到达站
            return trainStation.getStation().equals(ZhConverterUtil.toSimple(req.getBoardingStationName()))
                    && trainStation.getEndstation().equals(ZhConverterUtil.toSimple(req.getAlightingStationName()));
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        list.forEach(trainStation -> {
            // 封装返回参数
            TrainProductSeatH5DTO productSeatH5DTO = new TrainProductSeatH5DTO();
            productSeatH5DTO.setDepartureTime(LocalTime.parse(trainStation.getDeparturetime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(req.getEffectiveDate()));
            productSeatH5DTO.setTerminusTime(LocalTime.parse(trainStation.getArrivaltime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(req.getEffectiveDate()));
            productSeatH5DTO.setRunningTime(trainStation.getCosttime());
            productSeatH5DTO.setSupplierName("阿里云api");
            productSeatH5DTO.setTrainNumberName(trainStation.getTrainno());
            productSeatH5DTO.setProductSource(Constants.ALI);
            productSeatH5DTO.setBoardingStationName(req.getBoardingStationName());
            productSeatH5DTO.setAlightingStationName(req.getAlightingStationName());

            // 拆分座席
            List<ApiTrainProductSeatInfoDTO> seatlist = devideApiTrainProductToSeatInfo(trainStation);
            TrainProductSeatH5DTO finalProductSeatH5DTO = productSeatH5DTO;
            seatlist.forEach(seatInfo -> {
                List<TrainNumberSeatLevelCacheDTO> trainNumberSeatLevelCacheDTOS = finalProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS();
                if (CollectionUtils.isEmpty(trainNumberSeatLevelCacheDTOS)) {
                    finalProductSeatH5DTO.setTrainNumberSeatLevelCacheDTOS(new ArrayList<>());
                }
                TrainNumberSeatLevelCacheDTO seatLevelCacheDTO = new TrainNumberSeatLevelCacheDTO();
                seatLevelCacheDTO.setSeatLevelName(seatInfo.getSeatLevelName());
                seatLevelCacheDTO.setSeatNumber(seatInfo.getNum());


                // 获取外挂系统列表 计算服务费
                seatLevelCacheDTO.setIsMtrProduct(MtrTrainNumber.getTrainNumberList().contains(trainStation.getTrainno()) ? 1 : 0);
                // 获取外挂系统列表 计算服务费
                List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList;
                if (seatLevelCacheDTO.getIsMtrProduct() == 1) {
                    mainDataManualSystemAppDTOList = getMtrSystemAppDTOList(seatInfo.getPrice(), exchangeRate.getCrmExchangeRate());
                } else {
                    mainDataManualSystemAppDTOList = getDataManualSystemAppDTOList(seatInfo.getPrice(), exchangeRate.getCrmExchangeRate());
                }
                seatLevelCacheDTO.setMainDataManualSystemAppDTOList(mainDataManualSystemAppDTOList);

                // 人民币转港币
                BigDecimal price = (seatInfo.getPrice().multiply(exchangeRate.getCrmExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP);
                price = roundPrice(price);
                seatLevelCacheDTO.setPcPrice(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setPcChildPrice(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setH5Price(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setH5ChildPrice(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setIsAliProduct(1);
                finalProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS().add(seatLevelCacheDTO);
                trainProductSeatH5DTOS.add(finalProductSeatH5DTO);
            });
        });
        return trainProductSeatH5DTOS;
    }

    /**
     * 【【火車票】阿里雲，價格小數2位小於0.5向上補0.5，大於0.5向上補1塊】
     * https://www.tapd.cn/42567854/bugtrace/bugs/view/1142567854001006212
     *
     * @param b
     * @return
     */
    private BigDecimal roundPrice(BigDecimal b) {
        BigDecimal fractionalPart = b.remainder(BigDecimal.ONE);
        if (fractionalPart.compareTo(new BigDecimal("0.5")) < 0) {
            b = b.setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal("0.5"));
        } else if (fractionalPart.compareTo(new BigDecimal("0.5")) > 0) {
            b = b.setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal("1"));
        }
        return b;
    }

    /**
     * 拆分座席数据
     *
     * @param apiTrainProductDTO
     * @return
     */
    private List<ApiTrainProductSeatInfoDTO> devideApiTrainProductToSeatInfo(ApiTrainProductDTO apiTrainProductDTO) {
        List<ApiTrainProductSeatInfoDTO> list = new ArrayList<>();
        try {
            Class<? extends ApiTrainProductDTO> aClass = apiTrainProductDTO.getClass();
            Method[] methods = aClass.getDeclaredMethods();
            for (Method method : methods) {
                String methodName = method.getName();
                if (methodName.startsWith("getPrice")) {
                    String suffix = methodName.substring(methodName.indexOf("getPrice") + 8);
                    String price = (String) method.invoke(apiTrainProductDTO);
                    // 查询票价,如果为"-"代表没有该座次
                    if ("-".equals(price)) {
                        continue;
                    }
                    ApiTrainProductSeatInfoDTO apiTrainProductSeatInfoDTO = new ApiTrainProductSeatInfoDTO();
                    apiTrainProductSeatInfoDTO.setPrice(new BigDecimal(price));
                    String seatLevelName = SeatAliApiEnum.getName(suffix);
                    apiTrainProductSeatInfoDTO.setSeatLevelName(seatLevelName);
                    // 有票价查询余票数
                    Method declaredMethod = aClass.getDeclaredMethod("getNum" + suffix);
                    String num = (String) declaredMethod.invoke(apiTrainProductDTO);
                    apiTrainProductSeatInfoDTO.setNum(num);
                    list.add(apiTrainProductSeatInfoDTO);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 获取外挂系统列表
     *
     * @return
     */
    private List<MainDataManualSystemAppDTO> getDataManualSystemAppDTOList(BigDecimal price, BigDecimal crmRate) {
        List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList = new ArrayList<>();
        MainDataManualSystemAppDTO systemAppDTO = new MainDataManualSystemAppDTO();
        systemAppDTO.setId(MainDataManualSystemCode.MANUAL_2.getCode());
        systemAppDTO.setSupplierId(SupplierCode.SUPPLIER_2.getCode());
        systemAppDTO.setSupplierName(SupplierCode.SUPPLIER_2.getMsg());
        systemAppDTO.setSystemId(MainDataManualSystemCode.MANUAL_2.getCode());
        systemAppDTO.setSystemName(MainDataManualSystemCode.MANUAL_2.getMsg());
        systemAppDTO.setType(2);
        systemAppDTO.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        systemAppDTO.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
        systemAppDTO.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_2.getCode(), price.setScale(0, BigDecimal.ROUND_UP), crmRate));

        mainDataManualSystemAppDTOList.add(systemAppDTO);
        MainDataManualSystemAppDTO systemAppDTO_2 = new MainDataManualSystemAppDTO();
        systemAppDTO_2.setId(MainDataManualSystemCode.MANUAL_1.getCode());
        systemAppDTO_2.setSupplierId(SupplierCode.SUPPLIER_1.getCode());
        systemAppDTO_2.setSupplierName(SupplierCode.SUPPLIER_1.getMsg());
        systemAppDTO_2.setSystemId(MainDataManualSystemCode.MANUAL_1.getCode());
        systemAppDTO_2.setSystemName(MainDataManualSystemCode.MANUAL_1.getMsg());
        systemAppDTO_2.setType(2);
        systemAppDTO_2.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        systemAppDTO_2.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
        systemAppDTO_2.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_1.getCode(), price.setScale(0, BigDecimal.ROUND_UP), crmRate));
        mainDataManualSystemAppDTOList.add(systemAppDTO_2);
        return mainDataManualSystemAppDTOList;
    }


    /**
     * 获取外挂系统列表
     *
     * @return
     */
    private List<MainDataManualSystemAppDTO> getMtrSystemAppDTOList(BigDecimal crmRate, BigDecimal price) {
        List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList = new ArrayList<>();
        MainDataManualSystemAppDTO systemAppDTO = new MainDataManualSystemAppDTO();
        systemAppDTO.setId(MainDataManualSystemCode.MANUAL_3.getCode());
        systemAppDTO.setSupplierId(SupplierCode.SUPPLIER_3.getCode());
        systemAppDTO.setSupplierName(SupplierCode.SUPPLIER_3.getMsg());
        systemAppDTO.setSystemId(MainDataManualSystemCode.MANUAL_3.getCode());
        systemAppDTO.setSystemName(MainDataManualSystemCode.MANUAL_3.getMsg());
        systemAppDTO.setType(2);
        systemAppDTO.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        systemAppDTO.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
        systemAppDTO.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_3.getCode(), price, crmRate));
        systemAppDTO.setPrice(BigDecimal.ZERO);
        mainDataManualSystemAppDTOList.add(systemAppDTO);
        return mainDataManualSystemAppDTOList;
    }

    private BigDecimal getServiceChargeAmount(Long code, BigDecimal price, BigDecimal rate) {
        BigDecimal amount = new BigDecimal(0);
        if (code.equals(MainDataManualSystemCode.MANUAL_2.getCode())) {
            // 小于等于
            if (price.compareTo(new BigDecimal(100)) < 1) {
                amount = new BigDecimal(40);
                // 大于等于 && 小于等于
            } else if (price.compareTo(new BigDecimal(101)) > -1 && price.compareTo(new BigDecimal(400)) < 1) {
                amount = new BigDecimal(80);
                // 大于等于
            } else if (price.compareTo(new BigDecimal(401)) > -1) {
                amount = new BigDecimal(90);
            }
        } else {
            // 小于等于
            if (price.compareTo(new BigDecimal("199.5")) < 1) {
                amount = new BigDecimal(20);
                // 大于等于 && 小于等于
            } else if (price.compareTo(new BigDecimal(200)) > -1 && price.compareTo(new BigDecimal("299.5")) < 1) {
                amount = new BigDecimal(40);
                // 大于等于
            } else if (price.compareTo(new BigDecimal(300)) > -1) {
                amount = new BigDecimal(50);
            }
        }
        return amount;
    }

    /**
     * 根据币种ID获取汇率，获取汇率,
     *
     * @return
     */
    private MainDataCurrencyQueryDTO getExchangeRateByCurrencyId(Long currencyId) {
        MainDataCurrencyUpdateStatusReq mainDataCurrencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
        mainDataCurrencyUpdateStatusReq.setId(currencyId);
        Result<MainDataCurrencyQueryDTO> queryCurrencyRateResult = mainDataCurrencyService.query(mainDataCurrencyUpdateStatusReq);
        if (!queryCurrencyRateResult.isSuccess()) {
            SystemError defined = SystemError.getDefined(queryCurrencyRateResult.getCode());
            throw new BusinessException(defined);
        }
        return queryCurrencyRateResult.getData();
    }

    @Override
    public Result trainOrderPay(Long id, Integer paymentMethodCode) {
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        TrainOrder trainOrder = baseMapper.selectById(id);
        if (Objects.isNull(trainOrder)) {
            return Result.failed(SystemError.SYS_411);
        }
        if (nowLocalDateTime.isAfter(trainOrder.getPayExpireDate())) {
            // 支付超时
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14018);
        }
        if (!trainOrder.getPaymentStatus().equals(OrderPaymentStatus.UN_PAYMENT.getCode())) {
            // 支付超时
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14018);
        }

        PayCommonReq req = new PayCommonReq();
        //req.setOrderNumber(trainOrder.getOrderNumber());
        req.setSubject(SystemBusinessType.TRAIN_TICKET.getValue());
        req.setBody(SystemBusinessType.TRAIN_TICKET.getValue());
        req.setTotalFee(trainOrder.getOrderAmount());
        req.setOrderValidTime(trainOrder.getPayExpireDate());
        req.setCurrency(PayCurrency.HKD);
        req.setPaymentMethod(PaymentMethod.getByCode(paymentMethodCode));
        req.setNotifyUrl("/app/order/train/train-order/app/pay/notify");
        return payService.pay(req, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result trainOrderNotify(NotifyConsumeReq notifyConsumeReq) {
        log.info("火车票支付回调接口----入参：{}", JSON.toJSONString(notifyConsumeReq));
        if (!notifyConsumeReq.getOrderStatus().equals(PayOrderStatus.FULFIL.getStatus())) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14034, notifyConsumeReq.getOrderStatus(), notifyConsumeReq.getOrderNumber());
        }
        // 支付成功
        TrainOrder trainOrder = baseMapper.selectOne(new QueryWrapper<TrainOrder>().lambda()
                .eq(TrainOrder::getOrderNumber, notifyConsumeReq.getOrderNumber()));
        if (Objects.isNull(trainOrder)) {
            return Result.failed(SystemError.SYS_411);
        }
        trainOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_PAYMENT.getCode());
        trainOrder.setGmtModified(LocalDateTime.now());
        trainOrder.setModifiedId(trainOrder.getCreateId());

        // 默认已付款后预订状态为确认预订,外挂单需二次确认
        if (trainOrder.getOrderType() == 1) {
            trainOrder.setScheduledStatus(OrderScheduledStatus.CONFIRM_RESERVE.getCode());
        } else {
            //获取预订设置
            TrainProductDTO trainProductDTO = trainProductService.queryDetail(trainOrder.getTrainId());
            TrainProductReservationSettingsDTO reservationSetting = trainProductDTO.getTrainProductReservationSettingsDTO();
            if (reservationSetting != null) {
                // 是否二次确认
                Integer isConfirm = reservationSetting.getIsConfirm();
                if (isConfirm == 1) {
                    trainOrder.setScheduledStatus(OrderScheduledStatus.CONFIRM_RESERVE.getCode());
                } else {
                    trainOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
                }
            } else {
                trainOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
            }
        }
        baseMapper.updateById(trainOrder);

        // 添加收款记录
        TrainOrderCollection trainOrderCollection = new TrainOrderCollection();
        trainOrderCollection.setStandardAmount(trainOrder.getOrderAmount());
        trainOrderCollection.setCollectionAmount(trainOrder.getOrderAmount());
        trainOrderCollection.setCurrency(PayCurrency.HKD.getCode());
        trainOrderCollection.setOrderId(trainOrder.getId());
        trainOrderCollection.setStatus(OrderCollectionStatus.UN_REJECT.getCode());
        trainOrderCollection.setId(SnowflakeIdWorker.nextId());
        trainOrderCollection.setSalerId(trainOrder.getCreateId());
        trainOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
        trainOrderCollection.setGmtCreate(LocalDateTime.now());
        trainOrderCollection.setCollectionWay(PaymentMethod.getByCode(notifyConsumeReq.getPaymentMethod()).getName());
        trainOrderCollection.setCollectionWayId(PaymentMethod.getByCode(notifyConsumeReq.getPaymentMethod()).getPayRefundMethodId());

        // 设置收款单号
        trainOrderCollection.setCollectionNumber(TrainOrderManager.getCollectionNumber());
        trainOrderCollectionMapper.insert(trainOrderCollection);

        // 生成供应商订单
        UserDTO userDTO = sysUserService.queryCacheUser(trainOrder.getCreateId());
        List<TrainOrderTourist> touristList = trainOrderTouristMapper.selectListByKey(TrainOrderTourist::getOrderId, trainOrder.getId());
        payOrderToSupplier(trainOrder, touristList, userDTO);

        // 通知财务
        addCollection(trainOrder, userDTO, trainOrderCollection);
        updateStatusToAppUser(trainOrder.getId());
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result trainOrderCancel(TrainCancelOrderAppReq req) {
        TrainOrder trainOrder = baseMapper.selectById(req.getOrderId());
        if (trainOrder == null) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14020);
        }

        // 审批状态 ，取消订单审批通过或正在审批中，不允许重复操作
        if (ApprovalStatus.REVIEWING.getCode().equals(trainOrder.getCancelStatus()) ||
                ApprovalStatus.REVIEW_YES.getCode().equals(trainOrder.getCancelStatus())) {
            throw new BusinessException(SystemError.LOCAL_FUN_18013);
        }

        // 未支付, 直接取消成功
        if (trainOrder.getPaymentStatus().equals(OrderPaymentStatus.UN_PAYMENT.getCode())) {
            trainOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
            trainOrder.setGmtModified(LocalDateTime.now());
            baseMapper.updateById(trainOrder);
            return Result.success();
        }
        trainOrder.setCancelStatus(OrderCancelStatus.UNDER_APPROVAL.getCode());

        // 增加退款记录
        TrainOrderRefund trainOrderRefund = new TrainOrderRefund();
        trainOrderRefund.setOrderId(trainOrder.getId());
        trainOrderRefund.setRemark(req.getRemark());
        trainOrderRefund.setRefundReason(req.getRefundReason());
        trainOrderRefund.setStandardAmount(trainOrder.getOrderAmount());
        trainOrderRefund.setRefundNumber(OperateNumberGenerateUtil.generateRefundNumber(LocalDateTime.now()));
        trainOrderRefund.setCurrency(PayCurrency.HKD.getCode());
        trainOrderRefund.setRefundAmount(trainOrder.getOrderAmount());
        trainOrderRefund.setStatus(OrderRefundStatus.AUDITING.getCode());
        trainOrderRefund.setIsDeleted(IsDeletedCode.NO.getCode());
        trainOrderRefund.setId(SnowflakeIdWorker.nextId());
        trainOrderRefund.setGmtCreate(LocalDateTime.now());
        trainOrderRefund.setCreateId(trainOrder.getCreateId());
        trainOrderRefundMapper.insert(trainOrderRefund);

        // 审批电子流
        Result<ApprovalStartDTO> approvalResult = sysApprovalService.start(SystemBusinessType.TRAIN_TICKET.getCode(), SysApprovalType.CANCEL_TRAIN.getCode(), trainOrder.getId(), trainOrder.getCreateId(), null, null);
        if (!approvalResult.isSuccess()) {
            throw new BusinessException(SystemError.CUSTOM_ORDER_4044);
        }
        trainOrder.setRefundApprovalId(approvalResult.getData().getApprovalId());
        trainOrder.setGmtModified(LocalDateTime.now());
        baseMapper.updateById(trainOrder);
        updateStatusToAppUser(trainOrder.getId());
        return Result.success();
    }

    @Override
    public Result<TrainOrderDetailAppDTO> trainOrderDetail(Long id) {
        //根据订单id查询订单信息
        TrainOrder trainOrder = baseMapper.selectById(id);
        if (Objects.isNull(trainOrder)) {
            return Result.failed(SystemError.TRAIN_PRODUCT_14020);
        }
        TrainOrderDetailAppDTO trainOrderDetailDTO = EntityUtil.copy(trainOrder, TrainOrderDetailAppDTO.class);

        //订单状态
        if (trainOrderDetailDTO.getPaymentStatus() == null || OrderPaymentStatus.UN_PAYMENT.getCode().equals(trainOrderDetailDTO.getPaymentStatus())) {
            trainOrderDetailDTO.setOrderStatus(OrderStatus.UN_PAYMENT.getCode());
        } else if (trainOrderDetailDTO.getScheduledStatus() == null || OrderScheduledStatus.CONFIRM_RESERVE.getCode().equals(trainOrderDetailDTO.getScheduledStatus())) {
            trainOrderDetailDTO.setOrderStatus(OrderStatus.CONFIRM_RESERVE.getCode());
        } else if (OrderScheduledStatus.RESERVE_SUCCESS.getCode().equals(trainOrderDetailDTO.getScheduledStatus())) {
            trainOrderDetailDTO.setOrderStatus(OrderStatus.RESERVE_SUCCESS.getCode());
        } else if (OrderScheduledStatus.RESERVE_FAIL.getCode().equals(trainOrderDetailDTO.getScheduledStatus())) {
            trainOrderDetailDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());
        }


        // 设置付款状态名称,预订状态名称,取消状态名称,产品类型名称,订单来源名称
        trainOrderDetailDTO.setPaymentStatusName(OrderPaymentStatus.getOrderPaymentStatusName(trainOrderDetailDTO.getPaymentStatus()));
        trainOrderDetailDTO.setScheduledStatusName(OrderScheduledStatus.getOrderScheduledStatusName(trainOrderDetailDTO.getScheduledStatus()));
        trainOrderDetailDTO.setCancelStatusName(OrderCancelStatus.getOrderCancelStatusName(trainOrderDetailDTO.getCancelStatus()));
        trainOrderDetailDTO.setSourceName(OrderSource.getOrderSourceName(trainOrderDetailDTO.getSource()));

        //火车票订单旅客信息
        List<TrainOrderTourist> trainOrderTouristList = trainOrderTouristMapper.selectList(new QueryWrapper<TrainOrderTourist>().lambda().eq(TrainOrderTourist::getOrderId, id));
        if (!CollectionUtils.isEmpty(trainOrderTouristList)) {
            List<TrainOrderTouristAppDTO> trainOrderTouristDTOList = EntityUtil.copyList(trainOrderTouristList, TrainOrderTouristAppDTO.class);
            trainOrderDetailDTO.setTrainOrderTouristDTOList(trainOrderTouristDTOList);
        }

        if (trainOrder.getOrderType() == 0) {
            //火车信息
            TrainProductDTO busProductDTO = trainProductService.queryDetail(trainOrder.getTrainId());
            TrainProductReservationSettingsDTO trainProductReservationSettingsDTO = busProductDTO.getTrainProductReservationSettingsDTO();
            if (trainProductReservationSettingsDTO != null) {
                trainOrderDetailDTO.setBookingInformation(trainProductReservationSettingsDTO.getBookingInformation());
            }
            TrainProductH5DTO productH5DTO = EntityUtil.copy(busProductDTO, TrainProductH5DTO.class);

            // 经停站信息
            List<TrainStopStationCacheDTO> trainStopStationDTOList = EntityUtil.copyList(trainNumberService.queryStopStaionByTrainId(trainOrder.getTrainNumberId()), TrainStopStationCacheDTO.class);
            productH5DTO.setTrainStopStationCacheDTOS(trainStopStationDTOList);
            trainOrderDetailDTO.setTrainProductH5DTO(productH5DTO);
        } else {
            TrainProductH5DTO productH5DTO = EntityUtil.copy(trainOrder, TrainProductH5DTO.class);
            productH5DTO.setRunningTime(convertRunningTime(productH5DTO.getDepartureTime(), productH5DTO.getTerminusTime()));
            trainOrderDetailDTO.setTrainProductH5DTO(productH5DTO);
        }

        List<TrainOrderCollection> trainOrderCollections = trainOrderCollectionMapper.selectList(new QueryWrapper<TrainOrderCollection>().lambda()
                .eq(TrainOrderCollection::getOrderId, trainOrder.getId())
                .eq(TrainOrderCollection::getIsDeleted, IsDeletedCode.NO));
        if (!CollectionUtils.isEmpty(trainOrderCollections)) {
            TrainOrderCollection trainOrderCollection = trainOrderCollections.get(0);
            String collectionWay = trainOrderCollection.getCollectionWay();
            trainOrderDetailDTO.setPaymentMethod(collectionWay);
            trainOrderDetailDTO.setPaymentDateTime(trainOrderCollection.getGmtCreate());
        }


        return Result.success(trainOrderDetailDTO);
    }

    @Override
    public CallPayDTO getCallPayInfo(Long id) {
        TrainOrder trainOrder = trainOrderMapper.selectOne(Wrappers.<TrainOrder>lambdaQuery()
                .eq(TrainOrder::getId, id)
                .eq(TrainOrder::getPaymentStatus, OrderPaymentStatus.UN_PAYMENT.getCode())
                .eq(TrainOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .select(TrainOrder::getId, TrainOrder::getOrderNumber, TrainOrder::getReceivableAmount,
                        TrainOrder::getPayExpireDate, TrainOrder::getSalesmanId, TrainOrder::getPaymentStatus));
        if (trainOrder == null) {
            throw new BusinessException(SystemError.TRAIN_ORDER_24001);
        }
        CallPayDTO callPayDTO = EntityUtil.copy(trainOrder, CallPayDTO.class);
        callPayDTO.setOrderValidTime(trainOrder.getPayExpireDate());
        callPayDTO.setTotalFee(trainOrder.getReceivableAmount());
        callPayDTO.setCurrency(com.ctshk.common.enums.payment.PayCurrency.HKD);
        callPayDTO.setSubject("火车票订单支付");
        callPayDTO.setBody("火车票订单支付");
        return callPayDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result payment(NotifyConsumeReq notifyConsumeReq) {
        log.info("火车票支付回调接口----入参：{}", JSON.toJSONString(notifyConsumeReq));
        if (!notifyConsumeReq.getOrderStatus().equals(PayOrderStatus.FULFIL.getStatus())) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14034, notifyConsumeReq.getOrderStatus(), notifyConsumeReq.getOrderNumber());
        }
        // 支付成功
        TrainOrder trainOrder = baseMapper.selectOne(new QueryWrapper<TrainOrder>().lambda()
                .eq(TrainOrder::getOrderNumber, notifyConsumeReq.getOrderNumber()));
        if (Objects.isNull(trainOrder)) {
            return Result.failed(SystemError.SYS_411);
        }
        trainOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_PAYMENT.getCode());
        trainOrder.setGmtModified(LocalDateTime.now());
        trainOrder.setModifiedId(trainOrder.getCreateId());

        // 默认已付款后预订状态为确认预订,外挂单需二次确认
        if (trainOrder.getOrderType() == 1) {
            trainOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
        } else {
            //获取预订设置
            TrainProductDTO trainProductDTO = trainProductService.queryDetail(trainOrder.getTrainId());
            TrainProductReservationSettingsDTO reservationSetting = trainProductDTO.getTrainProductReservationSettingsDTO();
            if (reservationSetting != null) {
                // 是否二次确认
                Integer isConfirm = reservationSetting.getIsConfirm();
                if (isConfirm == 0) {
                    trainOrder.setScheduledStatus(OrderScheduledStatus.CONFIRM_RESERVE.getCode());
                } else {
                    trainOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
                }
            } else {
                trainOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
            }
        }
        baseMapper.updateById(trainOrder);

        // 添加收款记录
        TrainOrderCollection trainOrderCollection = new TrainOrderCollection();
        trainOrderCollection.setStandardAmount(trainOrder.getOrderAmount());
        trainOrderCollection.setCollectionAmount(trainOrder.getOrderAmount());
        trainOrderCollection.setCollectionWayId(PaymentMethod.getByCode(notifyConsumeReq.getPaymentMethod()).getPayRefundMethodId());
        trainOrderCollection.setCollectionWay(PaymentMethod.getByCode(notifyConsumeReq.getPaymentMethod()).getName());
        trainOrderCollection.setCurrency(PayCurrency.HKD.getCode());
        trainOrderCollection.setOrderId(trainOrder.getId());
        trainOrderCollection.setStatus(OrderCollectionStatus.UN_REJECT.getCode());
        trainOrderCollection.setId(SnowflakeIdWorker.nextId());
        trainOrderCollection.setSalerId(trainOrder.getCreateId());
        trainOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
        trainOrderCollection.setGmtCreate(LocalDateTime.now());
        //trainOrderCollection.setCreateId();

        // 设置收款单号
        trainOrderCollection.setCollectionNumber(TrainOrderManager.getCollectionNumber());
        trainOrderCollectionMapper.insert(trainOrderCollection);

        // 生成供应商订单
        UserDTO userDTO = sysUserService.queryCacheUser(trainOrder.getCreateId());
        List<TrainOrderTourist> touristList = trainOrderTouristMapper.selectListByKey(TrainOrderTourist::getOrderId, trainOrder.getId());
        payOrderToSupplier(trainOrder, touristList, userDTO);

        // 通知财务
        addCollection(trainOrder, userDTO, trainOrderCollection);
        updateStatusToAppUser(trainOrder.getId());

        //发送短信通知
        try {
            Map<String, String> smsParam = new HashMap<>();
            smsParam.put("orderid", trainOrder.getOrderNumber());
            smsParam.put("code", trainOrder.getQueryNumber());
            Result smsResult = userSmsService.sendOrderSms(SystemBusinessType.TRAIN_TICKET.getCode(), trainOrder.getContactMobileAreaCode(), trainOrder.getContactMobile(), smsParam);
            if (smsResult == null || !smsResult.isSuccess()) {
                throw new BusinessException(SystemError.SYS_437);
            }
            log.info("【火车票支付-支付回调】, 支付成功, 短信通知完成");
        } catch (BusinessException e) {
            log.error("短信发送失败");
        }

        return Result.success();
    }


    /**
     * @param d1 出发时间
     * @param d2 到达时间
     * @return
     */
    private String convertRunningTime(LocalDateTime d1, LocalDateTime d2) {
        if (d1 == null || d2 == null) {
            return null;
        }
        long minutes = Duration.between(d1, d2).toMinutes();
        long minute = minutes % 60L;
        long hour = minutes / 60L;
        return hour + "小时" + minute + "分";
    }

    /**
     * 下单支付成功后，对接供应商
     */
    private void payOrderToSupplier(TrainOrder trainOrder,
                                    List<TrainOrderTourist> touristList, UserDTO userDTO) {
        Long supplierId = 0L;
        String supplierName = "";
        String productNumber = "";
        String intendedForName = "";
        if (trainOrder.getOrderType() == 0) {
            // 查询产品
            TrainProductDTO trainProductDTO = trainProductService.queryDetail(trainOrder.getTrainId());
            supplierId = trainProductDTO.getSupplierId();
            supplierName = trainProductDTO.getSupplierName();
            productNumber = trainProductDTO.getProductCode();
            intendedForName = trainProductDTO.getIntendedForName();
        } else {
            // 查询外挂系统
            TrainManualOrder manualOrder = trainManualOrderMapper.selectOne(new QueryWrapper<TrainManualOrder>().lambda()
                    .eq(TrainManualOrder::getOrderId, trainOrder.getId()));
            if (manualOrder.getSystemId().equals(MainDataManualSystemCode.MANUAL_1.getCode())) {
                supplierId = SupplierCode.SUPPLIER_1.getCode();
                supplierName = SupplierCode.SUPPLIER_1.getMsg();
            } else if (manualOrder.getSystemId().equals(MainDataManualSystemCode.MANUAL_2.getCode())) {
                supplierId = SupplierCode.SUPPLIER_2.getCode();
                supplierName = SupplierCode.SUPPLIER_2.getMsg();
            }
        }


        SupplierOrderSystemTrainAddReq callReq = new SupplierOrderSystemTrainAddReq();
        callReq.setSupplierId(supplierId);
        callReq.setSupplierName(supplierName);
        callReq.setSupplierOrderType("2");
        callReq.setBusinessType(SystemBusinessType.TRAIN_TICKET.getCode());
        callReq.setReserveTypeId(SupplierReserveTypeEnum.TRAIN.getId());
        callReq.setProductType(trainOrder.getProductType());
        callReq.setSaleNumber(trainOrder.getOrderNumber());
        callReq.setSaleType(SalesMethod.SINGLE_SALE.getCode());
        callReq.setProductNumber(productNumber);
        callReq.setProductName(Assist.join(trainOrder.getBoardingStationName(), " - ", trainOrder.getAlightingStationName()));
        callReq.setTotalFee(trainOrder.getOrderAmount());
        if (userDTO != null) {
            callReq.setOriginalSaleNumber(Assist.toString(userDTO.getDeptId()));
            callReq.setDepartmentId(userDTO.getDeptId());
            callReq.setDepartment(userDTO.getDept());
        }
        callReq.setCurrencyId(CurrencyIdCode.HKD.getCode());
        callReq.setCurrency(CurrencyIdCode.HKD.getMsg());
        callReq.setPayableAmount(trainOrder.getReceivableAmount());
        callReq.setConfirmStatus(trainOrder.getScheduledStatus());
        List<SupplierSystemOrderTrainAddReq> orderCallReqList = new ArrayList<>();
        SupplierSystemOrderTrainAddReq orderCallReq = new SupplierSystemOrderTrainAddReq();
        orderCallReq.setOrderId(trainOrder.getId());
        // 适合人群
        orderCallReq.setSuitablePeople(intendedForName);
        List<SupplierSystemOrderTrainTicketAddReq> touristCallReqList = new ArrayList<>();
        Assist.forEach(touristList, tourist -> {
            SupplierSystemOrderTrainTicketAddReq touristCallReq = new SupplierSystemOrderTrainTicketAddReq();
            touristCallReq.setTrainId(null);
            touristCallReq.setOrderId(trainOrder.getId());
            touristCallReq.setGoLocationJson(Assist.buildJson("id", trainOrder.getDepartureCityId(), "name", trainOrder.getDepartureCityName()));
            touristCallReq.setDesLocationJson(Assist.buildJson("id", trainOrder.getArriveCityId(), "name", trainOrder.getArriveCityName()));
            touristCallReq.setTrainNumber(trainOrder.getTrainNumberName());
            touristCallReq.setStartTime(trainOrder.getDepartureTime());
            touristCallReq.setEndTime(null);
            touristCallReq.setTouristId(tourist.getId());
            touristCallReq.setTouristName(tourist.getTouristName());
            touristCallReq.setTouristTypeId(null);
            touristCallReq.setTouristType(tourist.getTouristType());
            touristCallReq.setSinglePrice(tourist.getTicketPrice());
            touristCallReqList.add(touristCallReq);
        });
        orderCallReq.setSupplierSystemOrderTrainTicketAddReqList(touristCallReqList);
        orderCallReqList.add(orderCallReq);
        callReq.setSupplierSystemOrderTrainAddReqList(orderCallReqList);
        supplierOrderService.addSystemTrain(callReq, trainOrder.getCreateId()).ok();
    }

    /**
     * 下单支付成功后，通知财务
     */
    private void addCollection(TrainOrder trainOrder, UserDTO userDTO, TrainOrderCollection trainOrderCollection) {
        List<BillAddCollectionReq> billAddCollectionList = Lists.newArrayList();

        //存放产品id列表
        List<Long> productIds = Lists.newArrayList();
        productIds.add(trainOrder.getTrainId());

        //资源信息列表
        List<String> resourceInfoList = Lists.newArrayList();
        resourceInfoList.add(trainOrder.getDepartureCityName() + '-' + trainOrder.getArriveCityName());

        String productNumber = "";
        if (trainOrder.getOrderType() == 0) {
            // 查询产品
            TrainProductDTO trainProductDTO = trainProductService.queryDetail(trainOrder.getTrainId());
            productNumber = trainProductDTO.getProductCode();
        } else {
            productNumber = Constants.ALI.toString();
        }

        //获取航班信息
        BillAddCollectionReq billAddCollectionReq = new BillAddCollectionReq();
        //        单号
        billAddCollectionReq.setBillNumber(trainOrderCollection.getCollectionNumber());
        //        业务类型
        billAddCollectionReq.setBusinessType(SystemBusinessType.TRAIN_TICKET.getCode());
        //        收款方式ID
        billAddCollectionReq.setCollectionWayId(trainOrderCollection.getCollectionWayId());
        //        收款方式
        billAddCollectionReq.setCollectionWayName(trainOrderCollection.getCollectionWay());
        //        收款类型ID
        billAddCollectionReq.setCollectionTypeId(CollectionTypeIdCode.FULL.getCode());
        //        收款类型
        billAddCollectionReq.setCollectionTypeName(CollectionTypeIdCode.FULL.getMsg());
        //        收款金额
        billAddCollectionReq.setCollectionAmount(trainOrderCollection.getCollectionAmount());
        //        币种ID
        billAddCollectionReq.setCurrencyId(trainOrderCollection.getCurrencyId());
        //        币种名称
        billAddCollectionReq.setCurrencyName(trainOrderCollection.getCurrency());
        // 获取对应汇率，计算支付金额
        BigDecimal exchangeRate = iMainDataCurrencyService.getExchangeRate(trainOrderCollection.getCurrency(), CurrencyRateExchangeConstant.MARKET_EXCHANGE_RATE_);
        billAddCollectionReq.setExchangeRate(exchangeRate.doubleValue());
        //        收款时间
        billAddCollectionReq.setCollectionTime(LocalDateTime.now());
        //        收款凭证JSON
        try { //避免出行json格式不对导致异常
            billAddCollectionReq.setCollectionVoucherJsonList(
                    JSONArray.parseArray(trainOrderCollection.getCollectionCertificateJson(), FileJson.class)
            );
        } catch (JSONException e) {
            e.printStackTrace();
        }
        //        销售单号
        billAddCollectionReq.setSaleOrderNumber(trainOrder.getOrderNumber());
        //        销售单ID
        billAddCollectionReq.setSaleOrderId(trainOrder.getId());
        //        产品ID
        billAddCollectionReq.setProductId(productIds);
        //        产品编号/团号
        billAddCollectionReq.setProductNumber(productNumber);
        //        产品名称
        billAddCollectionReq.setProductName(Assist.join(trainOrder.getBoardingStationName(), " - ", trainOrder.getAlightingStationName()));
        //        资源信息
        billAddCollectionReq.setResourceInfo(resourceInfoList);
        //        销售人员ID
        billAddCollectionReq.setSaleUserId(userDTO.getId());
        //        销售人员名称
        billAddCollectionReq.setSaleUserName(userDTO.getFullName());
        //        销售部门ID
        billAddCollectionReq.setSaleDeptId(userDTO.getDeptId());
        //        用户ID
        billAddCollectionReq.setUserId(userDTO.getId());
        billAddCollectionList.add(billAddCollectionReq);
        Result result = iFinanceBillService.addCollection(billAddCollectionList);
        if (result.getCode() != 0) {
            throw new BusinessException(SystemError.AIR_ORDER_15015, result.getMsg());
        }
    }

    /**
     * 代理下单 挂账
     */
    private void callFinanceOnAccount(TrainOrder trainOrder, TrainProductDTO trainProductDTO, TrainOrderCollection collectionReq, UserDTO userDTO) {
        //代理下单
        // 获取销售人员
        DispatchOrderRuleGetUserReq dispatchOrderRuleGetUserReq = new DispatchOrderRuleGetUserReq();
        dispatchOrderRuleGetUserReq.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        dispatchOrderRuleGetUserReq.setCompanyType(CompanyType.HK_CT.getCode());
        Result<Long> result = iDispatchOrderRuleService.getDispatchUserId(dispatchOrderRuleGetUserReq);
        if (!result.isSuccess()) {
            log.error("火车票下单 - 获取销售人失败msg:{}" + result.getMsg());
            throw new BusinessException(SystemError.getDefined(result.getCode()));
        }
        UserDTO saleUser = sysUserService.queryCacheUser(result.getData());

        if (trainOrder.getIsAgent() == 1) {
            List<UseQuotaReq> useQuotaReqs = new ArrayList<>();
            //挂账
            UseQuotaReq useQuotaReq = new UseQuotaReq();
            if (PayRefundMethod.AC.getId().equals(collectionReq.getCollectionWayId())) {
                useQuotaReq.setAccountType(1);

                //代理 账号为代理下单公司的ID
                if (BusConst.CLIENT_TYPE_AGENT.equals(trainOrder.getClientType())) {
                    useQuotaReq.setAccountId(trainOrder.getAgencyId());
                } else if (BusConst.CLIENT_TYPE_BIG.equals(trainOrder.getClientType())) {  //大客户
                    useQuotaReq.setAccountId(trainOrder.getBigClientId());
                    useQuotaReq.setBigClientId(trainOrder.getBigClientId());
                    useQuotaReq.setBigClientName(trainOrder.getBigClientName());
                }
            }


            useQuotaReq.setDeptId(userDTO.getDeptId());
            useQuotaReq.setAccountId(trainOrder.getAgencyId());
            useQuotaReq.setAmount(collectionReq.getCollectionAmount());
            //收款单号
            useQuotaReq.setBillNumber(collectionReq.getCollectionNumber());
            useQuotaReq.setBusinessType(SystemBusinessType.TRAIN_TICKET.getCode());
            useQuotaReq.setCollectionWayId(collectionReq.getCollectionWayId());
            useQuotaReq.setCollectionWayName(collectionReq.getCollectionWay());
            useQuotaReq.setCollectionTime(LocalDateTime.now());
//                    useQuotaReq.setCollectionVoucherJson(Lists.newArrayList(collectionReq.getCollectionCertificateJson()));
            useQuotaReq.setContactMobile(trainOrder.getContactMobile());

            BigDecimal exchangeRate = iMainDataCurrencyService.getExchangeRate(collectionReq.getCurrency(), CurrencyRateExchangeConstant.MARKET_EXCHANGE_RATE_);
            useQuotaReq.setExchangeRate(exchangeRate.doubleValue());

            useQuotaReq.setCurrencyId(collectionReq.getCurrencyId());
            useQuotaReq.setCurrencyName(Currency.getCurrencyById(collectionReq.getCurrencyId()).getCurrency());
            useQuotaReq.setUserId(saleUser.getId());

            if (trainProductDTO != null) {
                useQuotaReq.setProductId(trainProductDTO.getId());
                useQuotaReq.setProductName(Assist.join(trainOrder.getBoardingStationName(), " - ", trainOrder.getAlightingStationName()));
                useQuotaReq.setProductNumber(trainProductDTO.getProductCode());
                useQuotaReq.setSaleOrderId(trainOrder.getId());
                useQuotaReq.setSaleOrderNumber(trainOrder.getOrderNumber());
                useQuotaReq.setSaleUserId(trainOrder.getSalesmanId());
                useQuotaReq.setSaleUserName(trainOrder.getSalesmanName());
            }
            useQuotaReqs.add(useQuotaReq);

            if (Assist.isNotEmpty(useQuotaReqs)) {
                onAccountCurrencyQuotaService.useQuota(useQuotaReqs).ok();
            }
        }
    }

    /**
     * 生成火车票销售编号=PG+部门代码+员工编号+年后2位+月日4位+3位随机数字
     *
     * @param userDTO
     * @return
     */
    private String buildOrderNumber(UserDTO userDTO, LocalDateTime nowLocalDateTime) {
        String employeeNumber = userDTO.getEmployeeNumber();
        String deptCode = userDTO.getDeptCode();
        String date = DateUtil.fmt(nowLocalDateTime, "yyMMdd");
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 100));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("PG").append(deptCode).append(employeeNumber).append(date).append(randomNumber);
        return orderNumberSb.toString().toUpperCase();
    }


    /**
     * 根据总价计算应收价格，减去会员积分和优惠券
     *
     * @param trainOrder
     * @param orderAmount
     */
    private BigDecimal buildReceivableAmount(TrainOrder trainOrder, BigDecimal orderAmount) {
        BigDecimal receivableAmount = new BigDecimal(orderAmount.toString());
        //计算应收价格-是否使用积分
        if (trainOrder.getUsingPoints() != null) {
            BigDecimal usingPoints = new BigDecimal(String.valueOf(trainOrder.getUsingPoints()));
            // 校验会员积分是否充足
            checkMemberPoints(trainOrder, usingPoints);
            //计算应收价格-计算积分
            BigDecimal usingPointsCNY = usingPoints.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
            //人民币兑港币
            BigDecimal crmExchangeRate = getCrmExchangeRateByName(Currency.CNY.getSymbol());
            BigDecimal usingPointsHKD = usingPointsCNY.multiply(crmExchangeRate);
            if (receivableAmount.compareTo(usingPointsHKD) < 0) {
                // 总价减去积分价后为负数，不予许提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60007);
            }
            receivableAmount = receivableAmount.subtract(usingPointsHKD);
        }
        //计算应收价格-计算推广码（优惠券）
        if (trainOrder.getCouponId() != null) {
            // do something 推广码接口未写完，等待中
//            OperatePromotionQueryReq operatePromotionQueryReq = new OperatePromotionQueryReq();
//            operatePromotionQueryReq.setId(airportExpressOrder.getCouponId());
//            Result<OperatePromotionQueryDTO> operatePromotionQueryDTOResult = operatePromotionService.query(operatePromotionQueryReq);
        }
        return receivableAmount;
    }

    /**
     * 校验积分是否充足
     *
     * @param busOrder
     * @param usingPoints
     */
    private void checkMemberPoints(TrainOrder busOrder, BigDecimal usingPoints) {
        ContactQueryDTO contactQuery;
        try {
            CrmMemberQueryReq crmMemberQueryReq = new CrmMemberQueryReq(1, busOrder.getMemberId(), null);
            contactQuery = crmMemberService.queryMember(crmMemberQueryReq);
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw e;
            } else {
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60009);
            }
        }
        BigDecimal findMemberPoints = new BigDecimal(String.valueOf(contactQuery.getMember().getPoint1Value()));
        if (findMemberPoints.compareTo(usingPoints) < 0) {
            // 会员积分不足
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60008);
        }
    }

    /**
     * 根据币种名称获取汇率
     *
     * @param currencySy
     * @return
     */
    private BigDecimal getCrmExchangeRateByName(String currencySy) {
        MainDataCurrencyListReq mainDataCurrencyListReq = new MainDataCurrencyListReq();
        mainDataCurrencyListReq.setName(currencySy);
        PageResponse<MainDataCurrencyListDTO> list = iMainDataCurrencyService.list(mainDataCurrencyListReq);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(list.getRecords())) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60003);
        }
        return list.getRecords().get(0).getCrmExchangeRate();
    }

    /**
     * 根据币种名称获取汇率
     *
     * @param currencySy
     * @return
     */
    private MainDataCurrencyListDTO getExchangeRateByName(String currencySy) {
        MainDataCurrencyListReq mainDataCurrencyListReq = new MainDataCurrencyListReq();
        mainDataCurrencyListReq.setName(currencySy);
        PageResponse<MainDataCurrencyListDTO> list = mainDataCurrencyService.list(mainDataCurrencyListReq);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(list.getRecords())) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60003);
        }
        return list.getRecords().get(0);
    }

    /**
     * 构建订单ESDTO
     *
     * @param orderId
     * @return
     */
    public TrainOrderDetailDTO buildEsOrderDTO(Long orderId) {
        TrainOrder order = baseMapper.selectById(orderId);
        TrainOrderDetailDTO orderDTO = EntityUtil.copy(order, TrainOrderDetailDTO.class);
        return orderDTO;
    }

    /**
     * 生成查询号码，六位随机数字字符串
     *
     * @return
     */
    public static String generatorInquiryNumber() {
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        return randomNumber;
    }


    /**
     * 生成收據號碼：門市編號+員工編號+年後2位月日4位+B+時分秒6位+（S），
     * 例如：XS-C07884-200407-B-110008（S）
     *
     * @param userDTO
     * @return
     */
    public String generatorReceiptNumber(UserDTO userDTO, LocalDateTime nowLocalDateTime) {
        String symbol = "-";
        String employeeNumber = userDTO.getEmployeeNumber();
        String deptCode = userDTO.getDeptCode();
        String date = DateUtil.fmt(nowLocalDateTime, "yyMMdd");
        String time = DateUtil.fmt(nowLocalDateTime, "HHmmss");
        StringBuilder receiptNumberSb = new StringBuilder();
        receiptNumberSb.append("XS").append(symbol).append(deptCode).append(symbol)
                .append(employeeNumber).append(symbol)
                .append(date).append("-B-")
                .append(time).append("（S）");
        return receiptNumberSb.toString().toUpperCase();
    }

    private int insertReceipt(TrainOrder trainOrder, UserDTO userDTO, LocalDateTime nowLocalDateTime,String receiptTitle,Long officeId) {
        //生成收据单号
        String receiptNumber =generatorReceiptNumber(userDTO,nowLocalDateTime);
        TrainOrderReceipt trainOrderReceipt = new TrainOrderReceipt();
        trainOrderReceipt.setLicenseNo("351522");
        trainOrderReceipt.setSupportNo("29987333");
        //trainOrderReceipt.setAttention();
        trainOrderReceipt.setRemark(trainOrder.getRemark());
        trainOrderReceipt.setId(SnowflakeIdWorker.nextId());
        trainOrderReceipt.setOrderId(trainOrder.getId());
        trainOrderReceipt.setReceiptNo(receiptNumber);
        if (officeId==null||"".equals(officeId)){
            trainOrderReceipt.setBranch(userDTO.getDept());
        }else {
            trainOrderReceipt.setBranch(officeId.toString());
        }
        if(receiptTitle==null||receiptTitle==""){
            trainOrderReceipt.setGuest(trainOrder.getContactName());
        }else {
            trainOrderReceipt.setGuest(receiptTitle);
        }
        trainOrderReceipt.setPhone(trainOrder.getContactMobileAreaCode() + "-" + trainOrder.getContactMobile());
        trainOrderReceipt.setIsDeleted(IsDeletedCode.NO.getCode());
        trainOrderReceipt.setCreateId(userDTO.getId());
        trainOrderReceipt.setGmtCreate(nowLocalDateTime);
        trainOrderReceipt.setModifiedId(userDTO.getId());
        trainOrderReceipt.setGmtModified(nowLocalDateTime);
        return trainOrderReceiptMapper.insert(trainOrderReceipt);
    }

    /**
     * 异步发送订单数据到个人中心
     *
     * @param orderId 订单Id
     */
    public void sendOrderToAppUser(Long orderId) {
        CompletableFuture.runAsync(() -> {
            try {
                TrainOrderDetailDTO orderDTO = buildEsOrderDTO(orderId);
                orderEsService.saveOrderToEs(orderDTO, SystemBusinessType.TRAIN_TICKET);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 异步更新订单状态到个人中心
     */
    public void updateStatusToAppUser(Long orderId) {
        CompletableFuture.runAsync(() -> {
            try {
                TrainOrder order = baseMapper.selectById(orderId);
                orderEsService.updateStatusToEs(order.getId(), SystemBusinessType.TRAIN_TICKET.getCode(),
                        null, order.getPaymentStatus(), order.getScheduledStatus(),
                        order.getCancelStatus());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}
